<?php

namespace plugin\thinkphp\form\Driver;

use plugin\thinkphp\Admin;
use ExAdmin\ui\component\form\step\StepResult;
use ExAdmin\ui\contract\FormAbstract;
use ExAdmin\ui\response\Message;
use ExAdmin\ui\response\Response;
use plugin\thinkphp\traits\SoftDeleteHelp;
use think\facade\Db;
use think\helper\Arr;
use think\Model;
use think\model\concern\SoftDelete;
use think\model\relation\BelongsTo;
use think\model\relation\BelongsToMany;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use think\model\relation\MorphMany;
use think\model\relation\MorphOne;
use think\model\relation\MorphTo;

/**
 * @property Model $repository
 */
class Eloquent extends FormAbstract
{
    use SoftDeleteHelp;
    /**
     * 编辑数据
     * @param mixed $id
     * @return mixed
     */
    public function edit($id)
    {
        if ($this->trashed()) {
            $this->data = $this->repository->withTrashed()->find($id);
        } else {
            $this->data = $this->repository->find($id);
        }
        return $this->data;
    }

    public function trashed(): bool
    {
        return in_array(SoftDelete::class, class_uses_recursive($this->repository));
    }

    public function model()
    {
        return $this->repository;
    }

    /**
     * 数据保存
     * @param array $data
     * @return Message|Response
     */
    public function save(array $data, $id = null)
    {
        //验证数据
        $result = $this->form->validator()->check($data, !is_null($id));
        if ($result instanceof Response) {
            return $result;
        }
        $this->form->input($data);
        $result = $this->dispatchEvent('saving',[$this->form]);
        if ($result instanceof Message) {
            return $result;
        }

        $tableField = Db::connect($this->repository->getConnection())->getTableFields($this->repository->getTable());
        if (!is_null($id)) {
            $this->repository = $this->edit($id);
        }
        Db::connect($this->repository->getConnection())->startTrans();
        try {
            foreach ($this->form->input() as $field => $value) {
                if (in_array($field, $tableField)) {
                    $this->repository->$field = $value;
                }
            }
            $result = $this->repository->save();
            foreach ($this->form->input() as $field => $value) {
                if (method_exists($this->repository, $field)) {
                    $relationMethod = $this->repository->$field();
                    if ($relationMethod instanceof BelongsToMany) {
                        $relationMethod->detach();
                        $relationMethod->saveAll($value);
                    } elseif ($relationMethod instanceof HasOne || $relationMethod instanceof MorphOne || $relationMethod instanceof BelongsTo || $relationMethod instanceof MorphTo) {
                        $model = $this->repository->$field;
                        if(!$model) {
                            $model = $relationMethod->make();
                        }
                        $model->save($value);
                    } elseif ($relationMethod instanceof HasMany || $relationMethod instanceof MorphMany) {
                        $pk = $relationMethod->getModel()->getPk();
                        $realtionUpdateIds = array_column($value, $pk);
                        if (!empty($this->repository->$field)) {
                            $deleteIds = $this->repository->$field->column($pk);
                            $deleteIds = array_diff($deleteIds, $realtionUpdateIds);
                            if (count($deleteIds) > 0) {
                                $relationMethod->whereIn($pk, $deleteIds)
                                    ->when($this->isTrashed($relationMethod),function ($query) use($relationMethod){
                                        $this->useSoftDelete($relationMethod,$query);
                                    })
                                    ->delete();
                            }
                        }
                        $relationMethod->saveAll($value);
                    }
                }
            }
            Db::connect($this->repository->getConnection())->commit();
        } catch (\Exception $exception) {
            Db::connect($this->repository->getConnection())->rollback();
            if(env('APP_DEBUG')){
                throw $exception;
            }
        }
        $savedResult = $this->dispatchEvent('saved',[$this->form]);
        if ($savedResult instanceof Message) {
            return $savedResult;
        }
        if($this->form->isStepfinish()){
            $result = call_user_func($this->form->getSteps()->getFinish(),new StepResult($this->form,$result[$this->getPk()]));
            return Response::success($result,'',202);
        }
        if ($result) {
            return message_success(admin_trans('form.save_success'));
        }
        return message_error(admin_trans('form.save_fail'));
    }
    /**
     * 返回唯一标识字段，一般数据库主键自增字段
     * @return string
     */
    public function getPk(): string
    {
        return $this->repository->getPk();
    }

    /**
     * 获取数据
     * @param string $field 字段
     * @return mixed
     */
    public function get(string $field = null)
    {
        if (is_null($field)) {
            return $this->data->toArray();
        }
        $value = Arr::get($this->data, $field);
        if (method_exists($this->repository, $field)) {
            $relation = $this->repository->$field();
            if ($relation instanceof BelongsToMany) {
                if (empty($value)) {
                    return [];
                } else {
                    return $value->column($relation->getQuery()->getPk());
                }
            }
        }
        return $value;
    }


}
